#include"head.h"
#include"log.h"
#include "public.h"
#define MAXPATH 4096
#define MAPSIZE 104857600
#define HASHARR 65

int mkdirServe(const int NetFd,MYSQL *connection)
{
    INFO_LOG("执行mkdirServe\n");
    // 网络键值对切割接收数组
    char *agv[3] = { 0 };
    // 网络键值对接收数组
    char protocol[100] = { 0 };

    int ret = recv(NetFd,protocol,sizeof(protocol),0);
    // 日志信息
    switch (ret)
    {
    case 0:
        ERROR_LOG("对方断开连接！\n");
        return -1;
    case -1:
        ERROR_LOG("接收错误：mkdirServe未接受到protocol\n");
        return -1;
    }

    DEBUG_LOG("mkdirServe->protocol: %s\n",protocol);

    getToken(protocol,agv);

    DEBUG_LOG("mkdirServe->:name:%s,path:%s,param:%s\n",agv[0],agv[1],agv[2]);

    // 查询数据库，是否重复创建文件夹
    char respon[] = "创建失败\n";
    if(utils_mkdir(connection,agv[0],agv[1],agv[2]))
        strcpy(respon,"创建成功\n");
    DEBUG_LOG("mkdir%s",respon);

    // 返回给客户端mkdir成功与否
    ret = send(NetFd,respon,sizeof(respon),0);

    // 日志信息
    switch (ret)
    {
    case 0:
        ERROR_LOG("对方断开连接！\n");
        return -1;
    case -1:
        ERROR_LOG("接收错误：mkdirServe未成功返回respon\n");
        return -1;
    }

    INFO_LOG("mkdirServe执行完毕\n");

    return 0;
}

int cdServe(int NetFd,MYSQL *connection)
{
    INFO_LOG("执行cdServe\n");
    char protocol[100] = { 0 };
    char *agv[3];

    int ret = recv(NetFd,protocol,sizeof(protocol),0);
    // 日志信息
    switch (ret)
    {
    case 0:
        ERROR_LOG("对方断开连接！\n");
        return -1;
    case -1:
        ERROR_LOG("接收错误：cdServe未接受到protocol\n");
        return -1;
    }

    getToken(protocol,agv);

    char *path = agv[1];
    char *param = agv[2];
    // 如果是..或~或.命令怎无需查表
    if(strcmp(param,"..") == 0 || strcmp(param,"~") == 0 || strcmp(param,".") == 0)
        return 0;
    // 查表判断能否cd到目标路径
    char respon[] = "失败\n";
    if(utils_cd(connection,agv[0],agv[1],agv[2]))
        strcpy(respon,"成功\n");
    DEBUG_LOG("cdServe执行%s",respon);
    ret = send(NetFd,respon,sizeof(respon),0);
    // 日志信息
    switch (ret)
    {
    case 0:
        ERROR_LOG("对方断开连接！\n");
        return -1;
    case -1:
        ERROR_LOG("接收错误：cdServe未成功发送pos返回值\n");
        return -1;
    }

    INFO_LOG("cdServe执行完毕\n");

    return 0;

}

int lsServe(const int NetFd,MYSQL *connection)
{
    INFO_LOG("lsServe开始执行\n");

    char protocol[100] = { 0 };
    char *agv[3];

    int ret = recv(NetFd,protocol,sizeof(protocol),0);
    // 日志信息
    switch (ret)
    {
    case 0:
        ERROR_LOG("对方断开连接！\n");
        return -1;
    case -1:
        ERROR_LOG("接收错误：cdServe未接受到protocol\n");
        return -1;
    }

    getToken(protocol,agv);
    char *path = agv[1];
    char *param = agv[2];
    // 拼接ls参数
    if(strlen(param))
        sprintf(path,"%s/%s",path,param);
    DEBUG_LOG("lsServe->path:%s,param:%s\n",agv[1],agv[2]);

    char fileName[200] = { 0 };
    MYSQL_RES *result = utils_ls(connection,agv[0],agv[1]);
    MYSQL_ROW row;

    while((row = mysql_fetch_row(result)))
        for(int i = 0;i<mysql_num_fields(result);i++)
        {
            strcat(fileName,row[i]);
            strcat(fileName,"&");
        }
    mysql_free_result(result);

    DEBUG_LOG("lsServe->fileName:%s\n",fileName);

    ret = send(NetFd,fileName,sizeof(fileName),0);
    // 日志信息
    switch (ret)
    {
    case 0:
        ERROR_LOG("对方断开连接！\n");
        return -1;
    case -1:
        ERROR_LOG("发送错误：cdServe未成功发送fileName\n");
        return -1;
    }

    INFO_LOG("lsServe执行结束\n");

    return 0;
}
//传文件给客户端
int put_clientfile(int netfd,MYSQL* connection)
{
    server_train_t train;
    bzero(&train, 0);
    //接收protocal
    char protocal[1000];
    recv(netfd, &train.len, sizeof(off_t), MSG_NOSIGNAL);
    recv(netfd, train.trainBuf, train.len, MSG_NOSIGNAL);
    memcpy(protocal, train.trainBuf, train.len);

    //解析protocal
    char* nums[3];
    getToken(protocal,nums);
    bzero(&train, 0);
    //解析token

    //接收文件名
    /*
       recv(netfd, train.trainBuf, train.len, 0);
       char filename[MAXPATH];
       memcpy(filename, train.trainBuf, train.len);
       printf("file_name:%s\n",filename);
       */

    //拼接路径，使用路径打开文件
    //数据库创建之前
    char hash[HASHARR] = {0};
    get_file_hash(connection,nums[2],nums[1],nums[0],hash);
    bool name_exist=file_is_exist_byname(connection,nums[2],nums[1]);

    char file_path[MAXPATH];
    strcat(file_path,"../");
    strcat(file_path,hash);
    int file_fd = open(file_path, O_RDWR);
    if(file_fd==-1)
    {
        ERROR_LOG("打开文件失败,可能是路径错误\n");
    }
    //发送文件是否存在的信息
    send(netfd, &file_fd, sizeof(int), 0);


    bzero(&train, 0);
    // 获得文件信息
    struct stat stat_file;
    fstat(file_fd, &stat_file);
    train.len = stat_file.st_size;
    // 发送文件大小
    send(netfd, &train.len, sizeof(off_t), MSG_NOSIGNAL);
    if(train.len>MAPSIZE)   
    {

        char* addr = (char*)mmap(NULL,train.len,PROT_READ,MAP_SHARED,file_fd,0);
        if( addr ==NULL)
        {
            ERROR_LOG("文件映射失败\n");
        }
        send(netfd,addr,stat_file.st_size,MSG_NOSIGNAL);
        munmap(addr,train.len);
    }
    else
    {
        while(1){
            //send(netfd, &train.buf, train.len, MSG_NOSIGNAL);
            size_t nbytes = read(file_fd, train.trainBuf,train.len );
            printf("readbuf:%s\n",train.trainBuf);
            if(nbytes == -1){
                error(0,errno,"read");
            }
            if(nbytes < TRANINSIZE){
                send(netfd, &train.trainBuf, nbytes, MSG_NOSIGNAL);
                break;
            }
            send(netfd, &train.trainBuf,TRANINSIZE , MSG_NOSIGNAL);
        }
    }
    close(file_fd);
    return 0;
}

//接收客户端传来的文件
int get_clientfile(int netfd,MYSQL*connection){
    server_train_t train;

    bzero(&train, 0);
    //接收protocal
    char protocal[1000];
    recv(netfd, &train.len, sizeof(off_t), MSG_NOSIGNAL);
    recv(netfd, train.trainBuf, train.len, MSG_NOSIGNAL);
    memcpy(protocal, train.trainBuf, train.len);

    int file_status;
    recv(netfd, &file_status,sizeof(int),0);
    if(file_status == -1){
        printf("文件不存在，请检查输入后再试\n");
        return -1;
    }

    bzero(&train,0);
    //接收文件hash值
    char hash[HASHARR] = {0};
    recv(netfd, &train.len,sizeof(int),0);
    recv(netfd, hash, train.len, 0);
    printf("hash\n%s\n",hash);
    printf("\n");

    //解析protocal
    char* nums[3];
    getToken(protocal,nums);
    char file_path[MAXPATH];

    bool hash_exist=file_is_exist_byhash(connection,hash); 
    bool deleted=file_be_delete(connection,nums[2],nums[1]);
    bool name_exist=file_is_exist_byname(connection,nums[2],nums[1]);
    bool transfer=file_transfer_status(connection,hash);

    printf("hase:%d-deleted:%d-name:%d-transfer:%d\n",hash_exist,deleted,name_exist,transfer);

    enum TRANSFER trans;

    if(name_exist){
        if(hash_exist){
            if(transfer){
                trans=MIAO;
                //极速秒传
                //插入一条数据
                send(netfd,&trans,sizeof(int),0);
                //用户名引入token
                utils_puts(connection,nums[0],nums[1],nums[2],hash);
                return 0;
            }else{
                trans=DUANDIAN;
                printf("传输ing\n");

                send(netfd,&trans,sizeof(int),0);
                printf("传输ing\n");
                //断点续传
                continue_trans(connection,netfd,hash,nums[2]);
                printf("传输ing\n");

            }
        }else{
            send(netfd,&trans,sizeof(int),0);
            ERROR_LOG("用户试图创建同名文件\n");
            //发送信号位待确认
            trans=WRONG;
            send(netfd,&trans,sizeof(int),0);
            //禁止创建同名文件，返回错误码给客户端
            return 0;
        }
    }else{
        if(hash_exist){
            if(transfer){
                trans=MIAO;
                send(netfd,&trans,sizeof(int),0);
                //极速秒传
                utils_puts(connection,nums[0],nums[1],nums[2],hash);
            }else{
                trans=DUANDIAN;
                send(netfd,&trans,sizeof(int),0);
                //断点续传
                continue_trans(connection,netfd,hash,nums[2]);
            }
        }else{
            //正常上传
            //拼接路径，使用路径打开文件
    printf("%d-%d-%d-%d\n",hash_exist,name_exist,deleted,transfer);
    INFO_LOG("here:329\n");
            utils_puts(connection,nums[0],nums[1],nums[2],hash);
            trans=NORMAL;
    INFO_LOG("here:330\n");
            send(netfd,&trans,sizeof(int),0);
            strcat(file_path,"../file/");
            strcat(file_path,hash);
            //这里拼接hash值
            //strcat(file_path,nums[2]);
            int file_fd = open(file_path, O_CREAT | O_RDWR | O_TRUNC, 0666);
    INFO_LOG("here:serve:337\n");
            if(file_fd == -1){
                error(1, errno, "open");
            }
            bzero(&train, 0);
            // 接收文件大小
            recv(netfd, &train.len, sizeof(off_t), MSG_NOSIGNAL);
            //recv接收文件
            printf("文件大小：%d\n",train.len);
            long readbytes = 0;
            while(readbytes < train.len){
                ssize_t recvbytes = recv(netfd, train.trainBuf, TRANINSIZE, 0);
                if(recvbytes == -1){
                    error(1, errno, "recv");
                }
                if(recvbytes == 0) break;
                readbytes += recvbytes;
                ssize_t writebytes = write(file_fd,train.trainBuf,recvbytes);
                if(writebytes == -1){
                    error(1, errno, "write");
                }
            }
    INFO_LOG("here:360\n");
            if(readbytes==train.len)
            {
                if(!(change_file_transfer(connection,hash)))
                {
                    ERROR_LOG("文件状态修改失败\n");
                }
            }
            close(file_fd);
        }
    }
    printf("文件接收完毕\n");
    return 0;
}

